円グラフや散布図といったグラフは、JavaFXにおいてチャート・パッケージとしてまとめられている。細かな出力設定をするにはクラス継承やCSS設定が必要だが、デフォルトの見た目で出力する分には簡単にデータ出力できる。
■ チャートの種類
JavaFXで用意されているチャートの一覧を以下に示す。『Stacked○○』というクラスは積上グラフを表している。
グラフ |
クラス |
出力イメージ |
円グラフ |
PieChart |
|
折れ線グラフ |
LineChart |
|
面グラフ |
AreaChart
StackedAreaChart |
|
バブルチャート |
BubbleChart |
|
散布図 |
ScatterChart |
|
棒グラフ |
BarChart
StackedBarChart |
|
また、上記のイメージはデフォルト出力であるが、チャートもシーングラフの一種であるため、スタイルシートやエフェクトの適用により見た目を変えることができる。イベントハンドラの登録なども行うことができるため、チャート上にマウスを載せた場合に追加の情報を出力することも可能である。
■ サンプルコード
以下に各チャートを利用するサンプルコードを示す。
■ サンプルコード
package application_fx;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.BubbleChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestChart extends Application
{
public static void main(String[] args)
{
launch( args );
}
@Override
public void start(Stage primaryStage) throws Exception
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// シーングラフの作成
HBox root = new HBox();
VBox left = new VBox( 2.0 );
VBox right = new VBox( 2.0 );
root.getChildren().addAll( left , right );
// チャートを作成
left.getChildren().add( createPieChart() ); // 円グラフの追加
left.getChildren().add( createLineChart() ); // 折れ線グラフの追加
left.getChildren().add( createAreaChart() ); // 面グラフの追加
right.getChildren().add( createBubbleChart() ); // バブルチャートの追加
right.getChildren().add( createScatterChart() ); // 散布図の追加
right.getChildren().add( createBarChart() ); // 棒グラフの追加
// シーンの作成
Scene scene = new Scene( root , 1000 , 900 );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
/**
* 円グラフを作成
* 『国内Webブラウザシェア(2015年8月)』
* 元データ(https://webrage.jp/mobile/data/pc_browser_share.html)
* @return
*/
public Node createPieChart()
{
// 円グラフを作成
PieChart chart = new PieChart();
// グラフにデータを追加
ObservableList<PieChart.Data> data =
FXCollections.observableArrayList(
new PieChart.Data( "IE ( 41.09 )" , 41.09 ),
new PieChart.Data( "Chrome ( 31.76 )" , 31.76 ),
new PieChart.Data( "Firefox ( 12.52 )" , 12.52 ),
new PieChart.Data( "Safari ( 2.52 )" , 2.52 ),
new PieChart.Data( "other ( 12.11 )" , 12.11 )
);
chart.setData( data );
chart.setMinWidth( 500 );
// グラフの角度変更
chart.setStartAngle( 90 );
// タイトルを設定
chart.setTitle( "国内Webブラウザシェア(2015年8月)" );
chart.setLegendSide( Side.LEFT );
return chart;
}
/**
* 折れ線グラフを作成
* 『各国のGDP』
* 元データ(http://www.stat.go.jp/data/sekai/0116.htm)
* @return
*/
@SuppressWarnings("unchecked")
public Node createLineChart()
{
// 折れ線グラフ
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
LineChart<String, Number> chart = new LineChart<String, Number>( xAxis , yAxis );
chart.setMaxWidth( 500 );
// データを作成
Series< String , Number > series1 = new Series<String, Number>();
series1.setName( "日本" );
series1.getData().add( new XYChart.Data<String, Number>( "2000年" , 4730102 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2005年" , 4578144 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2010年" , 5510722 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2012年" , 5952575 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2013年" , 4920680 ) );
Series< String , Number > series2 = new Series<String, Number>();
series2.setName( "アメリカ" );
series2.getData().add( new XYChart.Data<String, Number>( "2000年" , 10284800 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2005年" , 13093700 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2010年" , 14964400 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2012年" , 16163200 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2013年" , 16768100 ) );
Series< String , Number > series3 = new Series<String, Number>();
series3.setName( "中国" );
series3.getData().add( new XYChart.Data<String, Number>( "2000年" , 1192836 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2005年" , 2287237 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2010年" , 5949785 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2012年" , 8229447 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2013年" , 9181204 ) );
// データを登録
chart.getData().addAll( series1 , series2 , series3 );
// タイトルを設定
chart.setTitle( "国内総生産(名目GDP,米ドル表示)" );
return chart;
}
/**
* 面グラフを作成
* 『ウイルス届出件数の推移』
* 元データ(https://www.ipa.go.jp/security/txt/2015/q2outline.html)
* @return
*/
@SuppressWarnings("unchecked")
public Node createAreaChart()
{
// 面グラフ
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
AreaChart<String, Number> chart = new AreaChart<String, Number>( xAxis , yAxis );
chart.setMaxWidth( 500 );
// データを作成
Series< String , Number > series1 = new Series<String, Number>();
series1.setName("ウィルス届出件数");
series1.getData().add( new XYChart.Data<String, Number>( "2014年\n4-6月" , 1292 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2014年\n7-9月" , 1298 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2014年\n10-12月" , 1010 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2015年\n1-3月" , 937 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2015年\n4-6月" , 772 ) );
Series< String , Number > series2 = new Series<String, Number>();
series2.setName("ウィルス被害件数");
series2.getData().add( new XYChart.Data<String, Number>( "2014年\n4-6月" , 1 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2014年\n7-9月" , 0 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2014年\n10-12月" , 0 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2015年\n1-3月" , 0 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2015年\n4-6月" , 2 ) );
// データを登録
chart.getData().addAll( series1 , series2 );
// タイトルを設定
chart.setTitle( "ウイルス届出件数の推移" );
return chart;
}
/**
* バブルチャートを作成
* 元データ:適当
* @return
*/
public Node createBubbleChart()
{
// x軸作成
NumberAxis xAxis = new NumberAxis();
xAxis.setLabel( "直帰率" );
xAxis.setAutoRanging( false );
xAxis.setUpperBound( 100 );
xAxis.setLowerBound( 0 );
xAxis.setTickUnit( 20 );
// y軸作成
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel( "新規訪問の割合" );
yAxis.setAutoRanging( false );
yAxis.setUpperBound( 100 );
yAxis.setLowerBound( 0 );
yAxis.setTickUnit( 20 );
// バブルチャート作成
BubbleChart<Number,Number> chart = new BubbleChart<Number,Number>( xAxis , yAxis );
chart.setMaxWidth( 500 );
// データを作成
Series< Number , Number > series1 = new Series<Number, Number>();
series1.setName("Webサイト訪問者数");
series1.getData().add( new XYChart.Data<Number, Number>( 1 , 1 , 30 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 10 , 10 , 20 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 80 , 20 , 2.5 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 40 , 57 , 8) );
series1.getData().add( new XYChart.Data<Number, Number>( 20 , 4 , 5 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 8 , 60 , 3 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 10 , 65 , 5 ) );
// データを登録
chart.getData().add( series1 );
// タイトルを設定
chart.setTitle( "Webサイト訪問傾向" );
return chart;
}
/**
* 散布図を作成
* 『東京における毎月1日の平均気温と湿度(2014年11月~2015年10月)』
* 元データ:(http://www.data.jma.go.jp/gmd/risk/obsdl/index.php)
* @return
*/
public Node createScatterChart()
{
// 散布図作成
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
ScatterChart<Number,Number> chart = new ScatterChart<Number,Number>( xAxis , yAxis );
chart.setMaxWidth( 500 );
// データを作成
xAxis.setLabel( "気温" );
yAxis.setLabel( "湿度" );
Series< Number , Number > series1 = new Series<Number, Number>();
series1.setName( "東京における平均気温と湿度" );
series1.getData().add( new XYChart.Data<Number, Number>( 16.8 , 85 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 13.5 , 92 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 3.7 , 41 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 4 , 32 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 6.9 , 79 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 13.9 , 76 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 20.5 , 63 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 23.6 , 51 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 20.5 , 98 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 30.5 , 76 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 23.7 , 96 ) );
series1.getData().add( new XYChart.Data<Number, Number>( 19.4 , 79 ) );
// データを登録
chart.getData().add( series1 );
// タイトルを設定
chart.setTitle( "東京における毎月1日の平均気温と湿度\n(2014年11月~2015年10月)" );
return chart;
}
/**
* 棒グラフを作成
* 『貿易相手国上位4カ国の推移』
* 元データ(http://www.customs.go.jp/toukei/suii/html/y3.pdf)
* @return
*/
@SuppressWarnings("unchecked")
public Node createBarChart()
{
// 棒グラフを作成
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
StackedBarChart<String,Number> chart = new StackedBarChart<String,Number>( xAxis , yAxis );
chart.setMaxWidth( 500 );
// データを作成
Series< String , Number > series1 = new Series<String, Number>();
series1.setName("アメリカ");
series1.getData().add( new XYChart.Data<String, Number>( "1995" , 184094 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2000" , 231347 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2005" , 218797 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2010" , 162854 ) );
series1.getData().add( new XYChart.Data<String, Number>( "2014" , 211919 ) );
Series< String , Number > series2 = new Series<String, Number>();
series2.setName("中国");
series2.getData().add( new XYChart.Data<String, Number>( "1995" , 54428 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2000" , 92158 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2005" , 208123 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2010" , 264985 ) );
series2.getData().add( new XYChart.Data<String, Number>( "2014" , 325579 ) );
Series< String , Number > series3 = new Series<String, Number>();
series3.setName("韓国");
series3.getData().add( new XYChart.Data<String, Number>( "1995" , 45500 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2000" , 55135 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2005" , 78413 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2010" , 79642 ) );
series3.getData().add( new XYChart.Data<String, Number>( "2014" , 89873 ) );
Series< String , Number > series4 = new Series<String, Number>();
series4.setName("台湾");
series4.getData().add( new XYChart.Data<String, Number>( "1995" , 40566 ) );
series4.getData().add( new XYChart.Data<String, Number>( "2000" , 58042 ) );
series4.getData().add( new XYChart.Data<String, Number>( "2005" , 68034 ) );
series4.getData().add( new XYChart.Data<String, Number>( "2010" , 66188 ) );
series4.getData().add( new XYChart.Data<String, Number>( "2014" , 67992 ) );
// データを登録
chart.getData().addAll( series1 , series2 , series3 , series4 );
// タイトルを設定
chart.setTitle( "貿易相手国上位4カ国の推移(億円)" );
return chart;
}
}
■ 実行結果
■ 解説
プログラムの流れはstart関数にまとめられており、43行目~48行目で各チャートをシーングラフに追加している。チャート作成のプログラムについては、create○○Chart関数にまとめている。プログラムを読むときのポイントとして『円グラフ』と『円グラフ以外』で分けて考えるとよい。プログラムを組む上で、両者の違いは以下のとおりである。
◇ 円グラフの利用
データはFXCollections.observableArrayList型のリストとして渡す。デフォルトでは時計の3時の方向から円グラフが開始されるため、setStartAngle関数により開始位置を12時の方向に変えるとわかりやすい(83行目)
◇ 円グラフ以外の利用
円グラフ以外のグラフは、すべて2つの軸を設定する必要がある。軸の種類には文字列の軸『CategoryAxis』と数値の軸『NumberAxis』が存在する。データはSeries型のリストとして渡し、1つのチャート上に複数のデータを持たせることができる。
■ 参照
- JavaFX: JavaFX UIコンポーネントの操作
- JavaDoc - パッケージjavafx.scene.chartの階層